package persistence.hibernate;

import java.util.Collection;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import persistence.Persistent;
import persistence.SingleSessionPersistence;
import util.Bug;
import util.Log;
import util.NotFoundException;
import util.Subsystem;

/**
 * persistence interface to hibenate.
 *
 * @author idan
 */
public class HibernatePersistenceController extends SingleSessionPersistence
{
	private SessionFactory sessionFactory ;
	private Session currentSession ;
	private Class<? extends Persistent> elementType ;

	/**
	 * @param type type of elements stored in the database.
	 * @param loadOnStartup whether to load elements from database or start a fresh one.
	 * @param sessionFactory factory to generate persistence sessions.
	 */
	public HibernatePersistenceController(final Class<? extends Persistent> type,
		final boolean loadOnStartup, final SessionFactory sessionFactory)
	{
		this.elementType = type ;
		this.sessionFactory = sessionFactory ;
		this.currentSession = this.sessionFactory.openSession() ;
		Log.getLogger(Subsystem.DATABASE_ACCESS).config("started") ;
	}

	/**
	 * @see persistence.PersistenceController#close()
	 */
	@Override
	public void close()
	{
		this.currentSession.close() ;
	}

	/**
	 * @see persistence.SingleSessionPersistence#commitTransaction()
	 */
	@Override
	public synchronized void commitTransaction() throws RuntimeException
	{
		super.commitTransaction() ;
		this.currentSession.getTransaction().commit() ;
	}

	/**
	 * @see persistence.PersistenceController#delete(long)
	 */
	@Override
	public void delete(final long id) throws NotFoundException
	{
		Persistent condemned = this.get(id) ;
		if (condemned != null)
		{
			this.currentSession.delete(condemned) ;
		}
		else
		{
			throw new NotFoundException(id) ;
		}
	}

	/**
	 * @see persistence.PersistenceController#deleteAll()
	 */
	@Override
	public void deleteAll()
	{
		this.currentSession.createQuery("delete " + this.elementType.getName()).executeUpdate() ;
	}

	/**
	 * @see persistence.PersistenceController#get(long)
	 */
	@Override
	public Persistent get(final long id)
	{
		Persistent result = (Persistent)this.currentSession.get(this.elementType, id) ;
		return result ;
	}

	/**
	 * @see persistence.PersistenceController#getAll()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public Collection<Persistent> getAll()
	{
		try
		{
			List<Persistent> objects = this.currentSession.createQuery("from " + this.elementType.getName()).list() ;
			return objects ;
		}
		catch (final ClassCastException e)
		{
			throw new Bug("inconsistent database") ;
		}
	}

	/**
	 * @see persistence.PersistenceController#put(persistence.Persistent)
	 */
	@Override
	public void put(final Persistent obj)
	{
		this.currentSession.save(obj) ;
	}

	/**
	 * @see persistence.PersistenceController#startTransaction()
	 */
	@Override
	public void startTransaction()
	{
		super.startTransaction() ;
		this.currentSession.beginTransaction() ;
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		return this.elementType.getName() ;
	}

	/**
	 * @see persistence.SingleSessionPersistence#commitToDatabase()
	 */
	@Override
	protected void commitToDatabase()
	{
		this.currentSession.flush() ;
	}

}
